// Copyright 2016-present the Material Components for iOS authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// swiftlint:disable function_body_length

import MaterialComponents.MaterialTextFields

final class TextFieldManualLayoutLegacySwiftExample: UIViewController {

  private enum LayoutConstants {
    static let largeMargin: CGFloat = 16
    static let smallMargin: CGFloat = 8

    static let floatingHeight: CGFloat = 84
    static let defaultHeight: CGFloat = 62

    static let stateWidth: CGFloat = 80
  }

  let scrollView = UIScrollView()

  let name: MDCTextField = {
    let name = MDCTextField()
    name.autocapitalizationType = .words
    return name
  }()

  let address: MDCTextField = {
    let address = MDCTextField()
    address.autocapitalizationType = .words
    return address
  }()

  let city: MDCTextField = {
    let city = MDCTextField()
    city.autocapitalizationType = .words
    return city
  }()
  let cityController: MDCTextInputControllerLegacyDefault

  let state: MDCTextField = {
    let state = MDCTextField()
    state.autocapitalizationType = .allCharacters
    return state
  }()

  let zip: MDCTextField = {
    let zip = MDCTextField()
    return zip
  }()
  let zipController: MDCTextInputControllerLegacyDefault

  let phone: MDCTextField = {
    let phone = MDCTextField()
    return phone
  }()

  let stateZip = UIView()

  var allTextFieldControllers = [MDCTextInputControllerLegacyDefault]()

  override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
    cityController = MDCTextInputControllerLegacyDefault(textInput: city)
    zipController = MDCTextInputControllerLegacyDefault(textInput: zip)
    super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
  }

  required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

  deinit {
    NotificationCenter.default.removeObserver(self)
  }

  override func viewDidLoad() {
    super.viewDidLoad()
    view.backgroundColor = UIColor(white:0.97, alpha: 1.0)

    title = "Legacy Manual Text Fields"

    setupScrollView()
    setupTextFields()

    updateLayout()

    registerKeyboardNotifications()
    addGestureRecognizer()

    let styleButton = UIBarButtonItem(title: "Style",
                                      style: .plain,
                                      target: self,
                                      action: #selector(buttonDidTouch(sender: )))
    self.navigationItem.rightBarButtonItem = styleButton
  }

  override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    scrollView.frame = view.bounds
  }

  func setupTextFields() {
    scrollView.addSubview(name)
    let nameController = MDCTextInputControllerLegacyDefault(textInput: name)
    name.delegate = self
    nameController.placeholderText = "Name"
    allTextFieldControllers.append(nameController)

    scrollView.addSubview(address)
    let addressController = MDCTextInputControllerLegacyDefault(textInput: address)
    address.delegate = self
    addressController.placeholderText = "Address"
    allTextFieldControllers.append(addressController)

    scrollView.addSubview(city)
    city.delegate = self
    cityController.placeholderText = "City"
    allTextFieldControllers.append(cityController)

    scrollView.addSubview(stateZip)

    stateZip.addSubview(state)
    let stateController = MDCTextInputControllerLegacyDefault(textInput: state)
    state.delegate = self
    stateController.placeholderText = "State"
    allTextFieldControllers.append(stateController)

    stateZip.addSubview(zip)
    zip.delegate = self
    zipController.placeholderText = "Zip Code"
    zipController.helperText = "XXXXX"
    allTextFieldControllers.append(zipController)

    scrollView.addSubview(phone)
    let phoneController = MDCTextInputControllerLegacyDefault(textInput: phone)
    phone.delegate = self
    phoneController.placeholderText = "Phone Number"
    allTextFieldControllers.append(phoneController)

    var tag = 0
    for controller in allTextFieldControllers {
      guard let textField = controller.textInput as? MDCTextField else { continue }
      textField.tag = tag
      tag += 1
    }

  }

  func setupScrollView() {
    view.addSubview(scrollView)

    scrollView.contentSize =
      CGSize(width: scrollView.bounds.width - 2 * LayoutConstants.largeMargin,
             height: 500.0)
  }

  func addGestureRecognizer() {
    let tapRecognizer = UITapGestureRecognizer(target: self,
                                               action: #selector(tapDidTouch(sender: )))
    self.scrollView.addGestureRecognizer(tapRecognizer)
  }

  func updateLayout() {
    let commonWidth = view.bounds.width - 2 * LayoutConstants.largeMargin
    var height = LayoutConstants.floatingHeight
    if let controller = allTextFieldControllers.first {
      height = controller.isFloatingEnabled ?
        LayoutConstants.floatingHeight : LayoutConstants.defaultHeight
    }

    name.frame = CGRect(x: LayoutConstants.largeMargin,
                        y: LayoutConstants.smallMargin,
                        width: commonWidth,
                        height: height)

    address.frame = CGRect(x: LayoutConstants.largeMargin,
                           y: name.frame.minY + height + LayoutConstants.smallMargin,
                           width: commonWidth,
                           height: height)

    city.frame = CGRect(x: LayoutConstants.largeMargin,
                        y: address.frame.minY + height + LayoutConstants.smallMargin,
                        width: commonWidth,
                        height: height)

    stateZip.frame = CGRect(x: LayoutConstants.largeMargin,
                            y: city.frame.minY + height + LayoutConstants.smallMargin,
                            width: commonWidth,
                            height: height)

    state.frame = CGRect(x: 0,
                         y: 0,
                         width: LayoutConstants.stateWidth,
                         height: height)

    zip.frame = CGRect(x: LayoutConstants.stateWidth + LayoutConstants.smallMargin,
                       y: 0,
                       width: stateZip.bounds.width - LayoutConstants.stateWidth -
                        LayoutConstants.smallMargin,
                       height: height)

    phone.frame = CGRect(x: LayoutConstants.largeMargin,
                         y: stateZip.frame.minY + height + LayoutConstants.smallMargin,
                         width: commonWidth,
                         height: height)
  }

  // MARK: - Actions

  @objc func tapDidTouch(sender: Any) {
    self.view.endEditing(true)
  }

  @objc func buttonDidTouch(sender: Any) {
    let alert = UIAlertController(title: "Floating Enabled",
                                  message: nil,
                                  preferredStyle: .actionSheet)
    let defaultAction = UIAlertAction(title: "Default (Yes)", style: .default) { _ in
      self.allTextFieldControllers.forEach({ (controller) in
        controller.isFloatingEnabled = true
      })
      self.updateLayout()
    }
    alert.addAction(defaultAction)
    let floatingAction = UIAlertAction(title: "No", style: .default) { _ in
      self.allTextFieldControllers.forEach({ (controller) in
        controller.isFloatingEnabled = false
      })
      self.updateLayout()
    }
    alert.addAction(floatingAction)
    present(alert, animated: true, completion: nil)
  }
}

extension TextFieldManualLayoutLegacySwiftExample: UITextFieldDelegate {
  func textField(_ textField: UITextField,
                 shouldChangeCharactersIn range: NSRange,
                 replacementString string: String) -> Bool {
    guard let rawText = textField.text else {
      return true
    }

    let fullString = NSString(string: rawText).replacingCharacters(in: range, with: string)

    if textField == zip {
      if let range = fullString.rangeOfCharacter(from: CharacterSet.letters),
        String(fullString[range]).characterCount > 0 {
        zipController.setErrorText("Error: Zip can only contain numbers",
                                   errorAccessibilityValue: nil)
      } else if fullString.characterCount > 5 {
        zipController.setErrorText("Error: Zip can only contain five digits",
                                   errorAccessibilityValue: nil)
      } else {
        zipController.setErrorText(nil, errorAccessibilityValue: nil)
      }
    } else if textField == city {
      if let range = fullString.rangeOfCharacter(from: CharacterSet.decimalDigits),
        String(fullString[range]).characterCount > 0 {
        cityController.setErrorText("Error: City can only contain letters",
                                    errorAccessibilityValue: nil)
      } else {
        cityController.setErrorText(nil, errorAccessibilityValue: nil)
      }
    }
    return true
  }

  func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    let index = textField.tag
    if index + 1 < allTextFieldControllers.count,
      let nextField = allTextFieldControllers[index + 1].textInput {
      nextField.becomeFirstResponder()
    } else {
      textField.resignFirstResponder()
    }

    return false
  }
}

// MARK: - Keyboard Handling

extension TextFieldManualLayoutLegacySwiftExample {
  func registerKeyboardNotifications() {
    let notificationCenter = NotificationCenter.default
    notificationCenter.addObserver(
      self,
      selector: #selector(keyboardWillShow(notif:)),
      name: UIResponder.keyboardWillShowNotification,
      object: nil)
    notificationCenter.addObserver(
      self,
      selector: #selector(keyboardWillShow(notif:)),
      name: UIResponder.keyboardWillChangeFrameNotification,
      object: nil)
    notificationCenter.addObserver(
      self,
      selector: #selector(keyboardWillHide(notif:)),
      name: UIResponder.keyboardWillHideNotification,
      object: nil)
  }

  @objc func keyboardWillShow(notif: Notification) {
    guard let frame = notif.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else {
      return
    }
    scrollView.contentInset = UIEdgeInsets(top: 0.0,
                                           left: 0.0,
                                           bottom: frame.height,
                                           right: 0.0)
  }

  @objc func keyboardWillHide(notif: Notification) {
    scrollView.contentInset = UIEdgeInsets()
  }
}

// MARK: - Status Bar Style

extension TextFieldManualLayoutLegacySwiftExample {
  override var preferredStatusBarStyle: UIStatusBarStyle {
    return .lightContent
  }
}

// MARK: - CatalogByConvention
extension TextFieldManualLayoutLegacySwiftExample {

  @objc class func catalogMetadata() -> [String: Any] {
    return [
      "breadcrumbs": ["Text Field", "[Legacy] Manual Layout (Swift)"],
      "primaryDemo": false,
      "presentable": false,
    ]
  }
}
